#ifndef __GLF_CORE_RTTI_H_INCLUDED__
#define __GLF_CORE_RTTI_H_INCLUDED__

#define DECLARE_RTTI_ROOT(base)					\
	typedef base Self;							\
	static  const glf::Rtti sRtti;				\
	virtual const glf::Rtti& GetRtti() const {	\
		return sRtti;							\
	}											\
	const char* GetRttiName() const {			\
		return GetRtti().mName;					\
	}											\
	static const char* GetTypename() {			\
		return sRtti.mName;						\
	}
	

#define DECLARE_RTTI(base, parent)	\
	DECLARE_RTTI_ROOT(base);		\
	typedef parent Parent;										

#define DEFINE_ROOT_RTTI(root) \
	const glf::Rtti root::sRtti(0, #root);

#define DEFINE_RTTI(derived) \
	const glf::Rtti derived::sRtti( &Parent::sRtti, #derived );

#include <glf/core/inlines.h>

namespace glf {

//from Alexandrescu's Modern C++ Design

template<class T, class U>
class Conversion {
	typedef char Small;
	class Big { char dummy[2]; };
	static Small Test(U);
	static Big Test(...);
	static T MakeT();

public:
	enum { exists = sizeof(Test(MakeT())) == sizeof(Small) };
};

//evaluates to true if U inherits from T publicly
#define GLF_INHERITSFROM(BASE, PARENT)	Conversion<const BASE*, const PARENT*>::exists

struct Rtti : private NonCopyable {

	static const int IS_RTTI = GLF_MAKE4CC('r', 't', 't', 'i');
	const int mIsRtti;
	const Rtti* mParentRtti;
	const char* mName;
	
	explicit Rtti(const Rtti* parent, const char* name) : 
		mIsRtti(IS_RTTI),
		mParentRtti(parent),
		mName(name) {
	}

	bool IsRtti() const {
		return mIsRtti == IS_RTTI;
	}
	
	bool IsDerivedFrom(const Rtti& typeInfo) const {
		const Rtti* self = this;

		while (self) {
			if(self == &typeInfo) {
				return true;
			}
			self = self->mParentRtti;
		}
		return false;
	}
};

template<typename T>
inline const Rtti& GetTypeInfoFromPtr(T*) {
	return T::sRtti;
}

template<typename T>
inline const Rtti& GetTypeInfo() {
	return T::sRtti;
}

template<typename UP, typename T>
inline UP* DynamicCast(T* obj) {
	const Rtti& typeInfoU = GetTypeInfo<UP>();
	
	if ( obj && obj->GetRtti().IsDerivedFrom( typeInfoU ) ) {
		return static_cast<UP*>(obj);
	}
	return 0;
}

template<typename UP, typename T>
inline const UP* DynamicCast(const T* obj) {
	const Rtti& typeInfoU = GetTypeInfo<UP>();
	
	if ( obj && obj->GetRtti().IsDerivedFrom( typeInfoU ) ) {
		return static_cast<const UP*>(obj);
	}
	return 0;
}


} //namespace glf

#endif
